﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using Civilisation_code.PJoueur;
using Civilisation_code.PCarte;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Civilisation_code.PPartie
{
    /// <summary>
    /// Classe Partie contenant toutes les informations de la partie
    /// </summary>
    /// <remarks>
    /// Produit dans le patron de conception Monteur
    /// </remarks>
    [Serializable]
    public class Partie : INotifyPropertyChanged
    {
        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        /// <summary>
        /// Création du singleton
        /// </summary>
        public static Partie INSTANCE;

        /// <summary>
        /// Numéro du joueur actif
        /// </summary>
        private int _numJoueurActif;
        public int NumJoueurActif
        {
            get
            {
                return _numJoueurActif;
            }
            set
            {
                _numJoueurActif = value;
                OnPropertyChanged("joueur_actif");

            }
        }

        /// <summary>
        /// Liste des joueurs actifs
        /// </summary>
        public List<Joueur> _joueurs { set; get; }

        /// <summary>
        /// Carte de la partie
        /// </summary>
        public Carte _carte { set; get; }

        /// <summary>
        /// Le numéro du tour en cours
        /// </summary>
        private int _nb_tour = 1;
        public int Nb_tour
        {
            set
            {
                _nb_tour = value;
                OnPropertyChanged("nb_tour");
            }
            get
            {
                return _nb_tour;
            }
        }
        
        /// <summary>
        /// Constructeur
        /// </summary>
        public Partie()
        {
            //Initialisation
            _joueurs = new List<Joueur>();
            NumJoueurActif = 0;
        }

        /// <summary>
        /// Récupération du joueur actif
        /// </summary>
        /// <returns>Joueur actif</returns>
        public Joueur getJoueurActif()
        {
            return _joueurs[NumJoueurActif]; 
        }
        /// <summary>
        /// Ajout d'un joueur dans la partie
        /// </summary>
        /// <param name="j">Joueur à ajouter</param>
        public void addJoueur(Joueur j){
               _joueurs.Add(j);
        }

        /// <summary>
        /// Met à jour le numéro du joueur actif et lance le traitement de nouveau tour du joueur
        /// </summary>
        public void joueurSuivant()
        {
            int anc = NumJoueurActif;
            NumJoueurActif = (NumJoueurActif + 1) % _joueurs.Count;
            if (NumJoueurActif < anc)
                Nb_tour++;
            _joueurs[NumJoueurActif].nouveauTour();
        }

        /// <summary>
        /// Tire au sort l'ordre des joueurs
        /// </summary>
        public void debut()
        {
            //Ordre de jeu aléatoire
            List<Joueur> tmp = new List<Joueur>();
            var rnd = new Random();
            while (_joueurs.Count != 0)
            {
                var index = rnd.Next(0, _joueurs.Count);
                tmp.Add(_joueurs[index]);
                _joueurs.RemoveAt(index);
            }
            _joueurs = tmp;


            NumJoueurActif = 0;
            _joueurs[NumJoueurActif].nouveauTour();
        }

        /// <summary>
        /// Charge une partie
        /// </summary>
        /// <param name="p">Emplacement du fichier</param>
        /// <returns>la partie chargée</returns>
        public static Partie charger(string p){
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(p, FileMode.Open, FileAccess.Read, FileShare.Read);

            Partie.INSTANCE = (Partie)formatter.Deserialize(stream);
            stream.Close();
            return Partie.INSTANCE;
        }

        /// <summary>
        /// Sauve une partie
        /// </summary>
        /// <param name="p">Emplacement du fichier</param>
        public void sauvegarder(string p)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(p, FileMode.Create, FileAccess.Write, FileShare.None);
            formatter.Serialize(stream,this);
            stream.Close();
        }

        /// <summary>
        /// Méthode qui regarde si il reste plusieurs joueurs en vie
        /// </summary>
        public void verifierFinPartie()
        {
            for (int i = 0; i < _joueurs.Count; i++)
            {
                Joueur j = _joueurs[i];
                if (j._villes.Count == 0 && j._unites.Count == 0)
                {
                    if (getJoueurActif() == j)
                        joueurSuivant();
                    _joueurs.Remove(j);
                    if (i < NumJoueurActif)
                        NumJoueurActif--;
                    OnPropertyChanged(j._nom);
                    i--;
                }
            }

            //Si il ne reste plus qu'un joueur en vie
            if(_joueurs.Count <= 1)
                OnPropertyChanged("partie_terminee");

        }
    }
}
